// -----------------------------
// Author: 		Dhaenens Gert 
// Creation: 	8/28/2013 7:04:30 PM				
// -----------------------------

#ifndef _LuaMethodInl_h
#define _LuaMethodInl_h

#include "LuaObject.h"
#include "LuaRef.h"
#include "LuaStackGuard.h"
#include "Lua.h"
#include "LuaStack.h"
#include "LuaDataType.h"
#include "LuaMethodSafeCall.h"

namespace ObjectLua
{

	namespace Internal
	{

		/*
		//	Used to actually bind
		//	the Method to Lua
		*/
		template<typename Class, typename R>
		void LuaMethod_0<Class,R>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Method lpMethod)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpMethod);

			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpMethod);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename Class, typename R>
		int LuaMethod_0<Class,R>::callback(lua_State* lpLuaState)
		{
			Type* lpMethod = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpMethod->call();
		}
		/*
		//	Call the Method
		*/
		template<typename Class, typename R>
		int LuaMethod_0<Class,R>::call() const
		{
			return MethodSafeCall_0<Class,R>()(m_lpLua,m_lpMethod);
		}




		/*
		//	Used to actually bind
		//	the Method to Lua
		*/
		template<typename Class, typename R, typename P0>
		void LuaMethod_1<Class,R,P0>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Method lpMethod)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpMethod);

			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpMethod);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename Class, typename R, typename P0>
		int LuaMethod_1<Class,R,P0>::callback(lua_State* lpLuaState)
		{
			Type* lpMethod = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpMethod->call();
		}
		/*
		//	Call the Method
		*/
		template<typename Class, typename R, typename P0>
		int LuaMethod_1<Class,R,P0>::call() const
		{
			return MethodSafeCall_1<Class,R,P0>()(m_lpLua,m_lpMethod);
		}




		/*
		//	Used to actually bind
		//	the Method to Lua
		*/
		template<typename Class, typename R, typename P0, typename P1>
		void LuaMethod_2<Class,R,P0,P1>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Method lpMethod)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpMethod);

			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpMethod);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename Class, typename R, typename P0, typename P1>
		int LuaMethod_2<Class,R,P0,P1>::callback(lua_State* lpLuaState)
		{
			Type* lpMethod = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpMethod->call();
		}
		/*
		//	Call the Method
		*/
		template<typename Class, typename R, typename P0, typename P1>
		int LuaMethod_2<Class,R,P0,P1>::call() const
		{
			return MethodSafeCall_2<Class,R,P0,P1>()(m_lpLua,m_lpMethod);
		}




		/*
		//	Used to actually bind
		//	the Method to Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2>
		void LuaMethod_3<Class,R,P0,P1,P2>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Method lpMethod)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpMethod);

			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpMethod);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2>
		int LuaMethod_3<Class,R,P0,P1,P2>::callback(lua_State* lpLuaState)
		{
			Type* lpMethod = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpMethod->call();
		}
		/*
		//	Call the Method
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2>
		int LuaMethod_3<Class,R,P0,P1,P2>::call() const
		{
			return MethodSafeCall_3<Class,R,P0,P1,P2>()(m_lpLua,m_lpMethod);
		}



		/*
		//	Used to actually bind
		//	the Method to Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3>
		void LuaMethod_4<Class,R,P0,P1,P2,P3>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Method lpMethod)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpMethod);

			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpMethod);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3>
		int LuaMethod_4<Class,R,P0,P1,P2,P3>::callback(lua_State* lpLuaState)
		{
			Type* lpMethod = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpMethod->call();
		}
		/*
		//	Call the Method
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3>
		int LuaMethod_4<Class,R,P0,P1,P2,P3>::call() const
		{
			return MethodSafeCall_4<Class,R,P0,P1,P2,P3>()(m_lpLua,m_lpMethod);
		}



		/*
		//	Used to actually bind
		//	the Method to Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4>
		void LuaMethod_5<Class,R,P0,P1,P2,P3,P4>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Method lpMethod)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpMethod);

			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpMethod);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4>
		int LuaMethod_5<Class,R,P0,P1,P2,P3,P4>::callback(lua_State* lpLuaState)
		{
			Type* lpMethod = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpMethod->call();
		}
		/*
		//	Call the Method
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4>
		int LuaMethod_5<Class,R,P0,P1,P2,P3,P4>::call() const
		{
			return MethodSafeCall_5<Class,R,P0,P1,P2,P3,P4>()(m_lpLua,m_lpMethod);
		}



		/*
		//	Used to actually bind
		//	the Method to Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
		void LuaMethod_6<Class,R,P0,P1,P2,P3,P4,P5>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Method lpMethod)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpMethod);

			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpMethod);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
		int LuaMethod_6<Class,R,P0,P1,P2,P3,P4,P5>::callback(lua_State* lpLuaState)
		{
			Type* lpMethod = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpMethod->call();
		}
		/*
		//	Call the Method
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
		int LuaMethod_6<Class,R,P0,P1,P2,P3,P4,P5>::call() const
		{
			return MethodSafeCall_6<Class,R,P0,P1,P2,P3,P4,P5>()(m_lpLua,m_lpMethod);
		}



		/*
		//	Used to actually bind
		//	the Method to Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
		void LuaMethod_7<Class,R,P0,P1,P2,P3,P4,P5,P6>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Method lpMethod)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpMethod);

			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpMethod);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
		int LuaMethod_7<Class,R,P0,P1,P2,P3,P4,P5,P6>::callback(lua_State* lpLuaState)
		{
			Type* lpMethod = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpMethod->call();
		}
		/*
		//	Call the Method
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
		int LuaMethod_7<Class,R,P0,P1,P2,P3,P4,P5,P6>::call() const
		{
			return MethodSafeCall_7<Class,R,P0,P1,P2,P3,P4,P5,P6>()(m_lpLua,m_lpMethod);
		}









		/*
		//	Used to actually bind
		//	the Method to Lua
		*/
		template<typename Class, typename R>
		void ConstLuaMethod_0<Class,R>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Method lpMethod)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpMethod);

			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpMethod);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename Class, typename R>
		int ConstLuaMethod_0<Class,R>::callback(lua_State* lpLuaState)
		{
			Type* lpMethod = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpMethod->call();
		}
		/*
		//	Call the Method
		*/
		template<typename Class, typename R>
		int ConstLuaMethod_0<Class,R>::call() const
		{
			return ConstMethodSafeCall_0<Class,R>()(m_lpLua,m_lpMethod);
		}




		/*
		//	Used to actually bind
		//	the Method to Lua
		*/
		template<typename Class, typename R, typename P0>
		void ConstLuaMethod_1<Class,R,P0>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Method lpMethod)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpMethod);

			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpMethod);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename Class, typename R, typename P0>
		int ConstLuaMethod_1<Class,R,P0>::callback(lua_State* lpLuaState)
		{
			Type* lpMethod = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpMethod->call();
		}
		/*
		//	Call the Method
		*/
		template<typename Class, typename R, typename P0>
		int ConstLuaMethod_1<Class,R,P0>::call() const
		{
			return ConstMethodSafeCall_1<Class,R,P0>()(m_lpLua,m_lpMethod);
		}




		/*
		//	Used to actually bind
		//	the Method to Lua
		*/
		template<typename Class, typename R, typename P0, typename P1>
		void ConstLuaMethod_2<Class,R,P0,P1>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Method lpMethod)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpMethod);

			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpMethod);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename Class, typename R, typename P0, typename P1>
		int ConstLuaMethod_2<Class,R,P0,P1>::callback(lua_State* lpLuaState)
		{
			Type* lpMethod = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpMethod->call();
		}
		/*
		//	Call the Method
		*/
		template<typename Class, typename R, typename P0, typename P1>
		int ConstLuaMethod_2<Class,R,P0,P1>::call() const
		{
			return ConstMethodSafeCall_2<Class,R,P0,P1>()(m_lpLua,m_lpMethod);
		}




		/*
		//	Used to actually bind
		//	the Method to Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2>
		void ConstLuaMethod_3<Class,R,P0,P1,P2>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Method lpMethod)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpMethod);

			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpMethod);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2>
		int ConstLuaMethod_3<Class,R,P0,P1,P2>::callback(lua_State* lpLuaState)
		{
			Type* lpMethod = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpMethod->call();
		}
		/*
		//	Call the Method
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2>
		int ConstLuaMethod_3<Class,R,P0,P1,P2>::call() const
		{
			return ConstMethodSafeCall_3<Class,R,P0,P1,P2>()(m_lpLua,m_lpMethod);
		}



		/*
		//	Used to actually bind
		//	the Method to Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3>
		void ConstLuaMethod_4<Class,R,P0,P1,P2,P3>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Method lpMethod)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpMethod);

			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpMethod);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3>
		int ConstLuaMethod_4<Class,R,P0,P1,P2,P3>::callback(lua_State* lpLuaState)
		{
			Type* lpMethod = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpMethod->call();
		}
		/*
		//	Call the Method
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3>
		int ConstLuaMethod_4<Class,R,P0,P1,P2,P3>::call() const
		{
			return ConstMethodSafeCall_4<Class,R,P0,P1,P2,P3>()(m_lpLua,m_lpMethod);
		}



		/*
		//	Used to actually bind
		//	the Method to Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4>
		void ConstLuaMethod_5<Class,R,P0,P1,P2,P3,P4>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Method lpMethod)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpMethod);

			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpMethod);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4>
		int ConstLuaMethod_5<Class,R,P0,P1,P2,P3,P4>::callback(lua_State* lpLuaState)
		{
			Type* lpMethod = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpMethod->call();
		}
		/*
		//	Call the Method
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4>
		int ConstLuaMethod_5<Class,R,P0,P1,P2,P3,P4>::call() const
		{
			return ConstMethodSafeCall_5<Class,R,P0,P1,P2,P3,P4>()(m_lpLua,m_lpMethod);
		}



		/*
		//	Used to actually bind
		//	the Method to Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
		void ConstLuaMethod_6<Class,R,P0,P1,P2,P3,P4,P5>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Method lpMethod)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpMethod);

			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpMethod);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
		int ConstLuaMethod_6<Class,R,P0,P1,P2,P3,P4,P5>::callback(lua_State* lpLuaState)
		{
			Type* lpMethod = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpMethod->call();
		}
		/*
		//	Call the Method
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
		int ConstLuaMethod_6<Class,R,P0,P1,P2,P3,P4,P5>::call() const
		{
			return ConstMethodSafeCall_6<Class,R,P0,P1,P2,P3,P4,P5>()(m_lpLua,m_lpMethod);
		}



		/*
		//	Used to actually bind
		//	the Method to Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
		void ConstLuaMethod_7<Class,R,P0,P1,P2,P3,P4,P5,P6>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Method lpMethod)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpMethod);

			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpMethod);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
		int ConstLuaMethod_7<Class,R,P0,P1,P2,P3,P4,P5,P6>::callback(lua_State* lpLuaState)
		{
			Type* lpMethod = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpMethod->call();
		}
		/*
		//	Call the Method
		*/
		template<typename Class, typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
		int ConstLuaMethod_7<Class,R,P0,P1,P2,P3,P4,P5,P6>::call() const
		{
			return ConstMethodSafeCall_7<Class,R,P0,P1,P2,P3,P4,P5,P6>()(m_lpLua,m_lpMethod);
		}
	}

}

#endif